Межсервисное взаимодействие MSI

Использовать очередь сообщений вместо HTTP-запроса целесообразно в ситуациях, когда тебе важно развязать сервисы по времени, обеспечить надёжность доставки, повысить масштабируемость и устойчивость системы.


Circuit Breaker

Circuit Breaker (предохранитель) — шаблон устойчивости, предотвращающий постоянные попытки вызвать неработающий сервис.
Три состояния:

Состояние Описание
Closed Все вызовы проходят
Open Вызовы блокируются (B недоступен)
Half-Open Периодически пробуем снова

Как работает:

  • Если подряд N запросов к B завершились с ошибкой → Circuit переходит в Open
  • Через заданный интервал → Half-Open: пробный вызов
  • Если успешно → снова Closed, иначе остаётся Open

Библиотеки:

  • .NET: Polly
  • Java: Resilience4j

Реализация ASP.NET Core:

dotnet add package Polly
dotnet add package Microsoft.Extensions.Http.Polly
using Polly;
using Polly.CircuitBreaker;

builder.Services.AddHttpClient("ExternalApi", client =>
{
    client.BaseAddress = new Uri("https://example.com/api/");
})
.AddTransientHttpErrorPolicy(policyBuilder =>
    policyBuilder.CircuitBreakerAsync(
        handledEventsAllowedBeforeBreaking: 3,
        durationOfBreak: TimeSpan.FromSeconds(30)
    )
);


Что такое Retry-политика?

Retry (повторный запрос) — это механизм, при котором клиент повторяет неудачный вызов через определённый промежуток времени.

Настраивается:

  • Кол-во попыток (например, 3 раза)
  • Интервал между попытками
  • Тип ошибок, при которых разрешён повтор (timeout, 5xx, network errors)

Rate Limiting

Политика при которой пользователю полагается сколько то запросов в какой то промежуток времени.
Реализация ASP.NET Core

dotnet add package AspNetCoreRateLimit

Config:

{
  "IpRateLimiting": {
    "EnableEndpointRateLimiting": true,
    "Period": "1m",
    "Limit": 100,
    "HttpStatusCode": 429
  }
}

Используй разные лимиты для разных клиентов/уровней доступа


Что такое Exponential Backoff?

Exponential backoff — это способ увеличения задержки между попытками:

Пример:

  • 1-я попытка: подождать 100 мс
  • 2-я попытка: 200 мс
  • 3-я: 400 мс
  • 4-я: 800 мс …

Это снижает нагрузку на умирающий сервис и повышает устойчивость.

Часто комбинируется с джиттером (jitter) — небольшим случайным смещением, чтобы избежать "шторма" повторов от всех клиентов.


Что такое Dead Letter Queue (DLQ)?

DLQ (очередь мёртвых сообщений) — это специальная очередь, куда попадают необработанные или ошибочные сообщения, например:

  • Сообщения, которые вызвали исключения N раз
  • Сообщения, которые не прошли проверку

Цель:

  • Не потерять сообщение
  • Дать возможность анализировать, логировать, обработать вручную

Используется в Kafka, RabbitMQ, AWS SQS и других брокерах.


Eventual consistency

Eventual consistency (временная согласованность) — это модель, при которой данные становятся согласованными не мгновенно, а со временем, при условии отсутствия новых обновлений.

Пример:

Пользователь оформил заказ → заказ сразу появляется в OrderService, а в AnalyticsService он появится через Kafka-событие через пару секунд.

Как с этим жить:

  • Понимать, что "свежие" данные могут быть неточны
  • Использовать индикаторы статуса (status: processing / confirmed)
  • Проектировать UX/flows с допущением на задержку

Кэш консистентность

Кэш консистентность — это вопрос синхронизации данных в кэше и в "истинном" источнике (обычно — БД).

Классическая проблема:

  • Обновили значение в БД
  • Но в кэше по-прежнему старая версия
  • Результат: клиент видит устаревшие данные

Виды консистентности кэша

Подход Принцип Плюсы Минусы
No consistency Кэш не инвалидируется Просто Могут быть баги, неактуальные данные
Write-through При UPDATE: сначала записываем в кэш, затем в БД Стабильный кэш Нужно синхронизировать ошибки
Write-behind Записываем в кэш, а БД обновляется асинхронно (через очередь) Быстро, удобно Сложно с потерей данных при падении
Cache-aside (lazy) Кэшируем только при чтении; при обновлении — инвалидация Гибко, руками управляем Требует дисциплины, можно забыть
Read-through Все чтения идут через кэш-обёртку, которая сама обновляет кэш Удобно и безопасно Потенциально сложнее в реализации

Когда использовать Redis, а когда In-Memory Cache

Критерий In-Memory (MemoryCache / IMemoryCache) Redis (StackExchange.Redis)
Масштабируемость Только внутри одного инстанса Распределённый: работает между всеми сервисами
Объём кэша Ограничен ОЗУ текущего процесса Redis может использовать ГБ-памяти, LRU eviction
Изоляция данных Кэш изолирован, быстро Redis — общий кэш, данные доступны всем
Инвалидация по событию Нужно синхронизировать вручную Можно использовать Pub/Sub, списки, TTL
Скорость доступа Быстрее (из RAM, без сетевого запроса) Быстрее, чем БД, но сетевой вызов
Устойчивость При падении сервиса кэш теряется Redis можно настроить с репликами и сохранением
В проде на Kubernetes Только для узкоспециализированных задач Лучший выбор для продакшена
Когда использовать - Одно-узловой сервис
- Локальный кеш
- Например, частые вычисления
- Распределённые сервисы
- Shared session
- Rate limiting
- Background worker sharing

Авторизация и аутентификация

Аутентификация Проверка кто ты — удостоверение личности (логин, токен, сертификат)
Авторизация Проверка что тебе разрешено — доступ к конкретным ресурсам или действиям

JWT

Плюсы: просто, кроссплатформенно и не требует дополнительного сервиса
Минусы: Сложно масштабировать

Алгоритм такой:
Пользователь отправляет логин и пароль, сервис с использованием внутреннего секрета шифрует и закладывает в accessToken информацию о том когда он истекает и что это за пользователь, а также генерирует рефреш токен и сохранет его в бд. После возвращает оба токена пользователю.

Oath 2.0

OpenID предназначен для аутентификации — то есть для того, чтобы понять, что этот конкретный пользователь является тем, кем представляется. Например, с помощью OpenID некий сервис Ололо может понять, что зашедший туда пользователь, это именно Рома Новиков с Mail.Ru. При следующей аутентификации Ололо сможет его опять узнать и понять, что, это тот же Рома, что и в прошлый раз.

OAuth же является протоколом авторизации, то есть позволяет выдать права на действия, которые сам Ололо сможет производить в Mail.Ru от лица Ромы. При этом Рома после авторизации может вообще не участвовать в процессе выполнения действий, например, Ололо сможет самостоятельно заливать фотографии на Ромин аккаунт.